#include <coroutine>
#include <iostream>
#include <memory>
#include <thread>
#include <chrono>
#include <optional>

// 协程返回类型定义
struct Task {
    // Promise 类型定义协程的行为和返回值
    struct promise_type {
        std::optional<int> value;  // 存储协程返回的值，用 optional 包装以支持延迟赋值
        // 初始挂起，协程启动即挂起，等待显式恢复
        std::suspend_always initial_suspend() { return {}; }
        // 最终挂起，协程结束时挂起，防止协程退出后立即销毁资源
        std::suspend_always final_suspend() noexcept { return {}; }
        // 获取协程的返回对象，链接协程与外部世界
        Task get_return_object() { return Task{this}; }
        // 设置协程的返回值
        void return_value(int v) { value = v; }
        // 异常处理，若协程内部抛出未捕获异常，则结束程序
        void unhandled_exception() { std::exit(1); }
        // 生成暂停点并返回值给调用者，再次挂起协程
        auto yield_value(int v) {
            value = v;
            return std::suspend_always{};
        }
    };

    // 尝试恢复协程执行，如果协程已完成，则返回 false
    bool resume() {
        if (handle.done()) {
            return false;
        }
        handle.resume();
        return true;
    }

    // 获取协程处理完成后的结果
    int get() {
        return *handle.promise().value;
    }

    // 构造函数和析构函数管理协程的生命周期
    Task(promise_type* p) : handle(std::coroutine_handle<promise_type>::from_promise(*p)) {}
    ~Task() {
        if (handle) handle.destroy();
    }

private:
    std::coroutine_handle<promise_type> handle;  // 内部保存对应协程的句柄
};

// 异步函数定义，模拟长时间的数据处理任务
Task loadDataAsync(int data) {
    // 模拟耗时操作
    std::this_thread::sleep_for(std::chrono::seconds(2));
    // 通过 co_return 语句返回处理结果，协程在此挂起并将控制权交还给调用者
    co_return data * 2;
}

int main() {
    // 启动异步任务
    auto dataLoader = loadDataAsync(10);
    
    // 同时执行其他任务
    std::cout << "Doing other work while waiting for data..." << std::endl;
    
    // 循环调用 resume 直到协程执行完成
    while (dataLoader.resume());

    // 获取异步任务的结果并打印
    int result = dataLoader.get();
    std::cout << "Data loaded: " << result << std::endl;

    return 0;
}